/********************************************************************************************************
 * @file    keyboard.c
 *
 * @brief   This is the source file for Telink RISC-V MCU
 *
 * @author  Driver Group
 * @date    2019
 *
 * @par     Copyright (c) 2019, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *
 *          Licensed under the Apache License, Version 2.0 (the "License");
 *          you may not use this file except in compliance with the License.
 *          You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 *          Unless required by applicable law or agreed to in writing, software
 *          distributed under the License is distributed on an "AS IS" BASIS,
 *          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *          See the License for the specific language governing permissions and
 *          limitations under the License.
 *
 *******************************************************************************************************/
#include "tl_common.h"
#include "keyboard.h"
#include "../usbstd/usbkeycode.h"

#if (defined(KB_DRIVE_PINS) && defined(KB_SCAN_PINS))

unsigned int drive_pins[] = KB_DRIVE_PINS;
unsigned int scan_pins[]  = KB_SCAN_PINS;

    #if (STUCK_KEY_PROCESS_ENABLE)
unsigned char stuckKeyPress[ARRAY_SIZE(drive_pins)];
    #endif

_attribute_data_retention_ kb_data_t     kb_event;
_attribute_data_retention_ kb_data_t     kb_event_cache;
_attribute_data_retention_ unsigned char deepback_key_state;
_attribute_data_retention_ unsigned int  deepback_key_tick;

    #ifndef SCAN_PIN_50K_PULLUP_ENABLE
        #define SCAN_PIN_50K_PULLUP_ENABLE 0
    #endif

    #ifndef KB_MAP_DEFAULT
        #define KB_MAP_DEFAULT 1
    #endif

    #ifndef KB_LINE_MODE
        #define KB_LINE_MODE 0
    #endif

    #ifndef KB_LINE_HIGH_VALID
        #define KB_LINE_HIGH_VALID 1
    #endif

    #ifndef KB_KEY_FLASH_PIN_MULTI_USE
        #define KB_KEY_FLASH_PIN_MULTI_USE 0
    #endif

    #ifndef KB_HAS_CTRL_KEYS
        #define KB_HAS_CTRL_KEYS 1
    #endif

    #ifndef KB_RM_GHOST_KEY_EN
        #define KB_RM_GHOST_KEY_EN 0
    #endif

    #ifndef KB_HAS_FN_KEY
        #define KB_HAS_FN_KEY 1
    #endif

    #ifndef KB_DRV_DELAY_TIME
        #define KB_DRV_DELAY_TIME 10
    #endif

    #ifndef KB_STANDARD_KEYBOARD
        #define KB_STANDARD_KEYBOARD 0
    #endif

    #if KB_REPEAT_KEY_ENABLE

        #ifndef KB_REPEAT_KEY_INTERVAL_MS
            #define KB_REPEAT_KEY_INTERVAL_MS 200
        #endif
        #ifndef KB_REPEAT_KEY_NUM
            #define KB_REPEAT_KEY_NUM 4
        #endif
static const unsigned char kb_map_repeat[KB_REPEAT_KEY_NUM] = KB_MAP_REPEAT;

repeatKey_t repeat_key = {
    0,
    0,
    0,
    0,
    U32_MAX,
};

    #endif

typedef unsigned char kb_k_mp_t[ARRAY_SIZE(drive_pins)]; //typedef unsigned char kb_k_mp_t[8]

    #if KB_MAP_DEFAULT

        #ifndef KB_MAP_NORMAL
static const unsigned char kb_map_normal[ARRAY_SIZE(scan_pins)][ARRAY_SIZE(drive_pins)] = {
    {VK_PAUSE,    VK_POWER,     VK_EURO,      VK_SLEEP,     VK_RCTRL,      VK_WAKEUP,    VK_CTRL,     VK_F5         },
    {VK_Q,        VK_TAB,       VK_A,         VK_ESC,       VK_Z,          VK_NCHG,      VK_TILDE,    VK_1          },
    {VK_W,        VK_CAPITAL,   VK_S,         VK_K45,       VK_X,          VK_CHG,       VK_F1,       VK_2          },
    {VK_E,        VK_F3,        VK_D,         VK_F4,        VK_C,          VK_ROMA,      VK_F2,       VK_3          },
    {VK_R,        VK_T,         VK_F,         VK_G,         VK_V,          VK_B,         VK_5,        VK_4          },
    {VK_U,        VK_Y,         VK_J,         VK_H,         VK_M,          VK_N,         VK_6,        VK_7          },
    {VK_I,        VK_RBRACE,    VK_K,         VK_F6,        VK_COMMA,      VK_K56,       VK_EQUAL,    VK_8          },
    {VK_O,        VK_F7,        VK_L,         VK_RMB,       VK_PERIOD,     VK_APP,       VK_F8,       VK_9          },
    {VK_P,        VK_LBRACE,    VK_SEMICOLON, VK_QUOTE,     VK_BACKSLASH,  VK_SLASH,     VK_MINUS,    VK_0          },
    {VK_SCR_LOCK, VK_C9R1,      VK_FN,        VK_ALT,       VK_MMODE,      VK_RALT,      VK_C9R6,     VK_PRINTSCREEN},
    {VK_K14,      VK_BACKSPACE, VK_BACKSLASH, VK_F11,       VK_ENTER,      VK_F12,       VK_F9,       VK_F10        },
    {VK_HOME,     VK_LEFT,      VK_END,       VK_SPACE,     VK_NUM_LOCK,   VK_DOWN,      VK_DELETE,   VK_POWER      },
    {VK_UP,       VK_NONE,      VK_DOWN,      VK_INSERT,    VKPAD_SLASH,   VK_RIGHT,     VK_INSERT,   VK_SLEEP      },
    {VK_PAGE_UP,  VK_RIGHT,     VK_PAGE_DOWN, VKPAD_PERIOD, VKPAD_ASTERIX, VKPAD_MINUS,  VK_PAGE_UP,  VK_PAGE_DOWN  },
    {VKPAD_PLUS,  VK_K107,      VKPAD_ENTER,  VK_UP,        VK_PLAY_PAUSE, VK_LEFT,      VK_HOME,     VK_END        },
    {VK_WAKEUP,   VK_SHIFT,     VK_RSHIFT,    VK_VOL_DN,    VK_VOL_UP,     VK_NEXT_TRK,  VK_PREV_TRK, VK_MEDIA      },
    {VK_MAIL,     VK_WIN,       VK_W_FORWARD, VK_W_STOP,    VK_W_BACK,     VK_W_REFRESH, VK_W_MUTE,   VK_W_SRCH     },
    {VK_KCL,      VK_W_FAV,     VK_RWIN,      VK_MY_COMP,   VK_STOP,       VK_CAL,       VK_WEB,      VK_KCR        },
};
        #else
static const unsigned char kb_map_normal[ARRAY_SIZE(scan_pins)][ARRAY_SIZE(drive_pins)] = KB_MAP_NORMAL;
        #endif

#if KB_STANDARD_KEYBOARD
        #ifndef KB_MAP_NUM
static const unsigned char kb_map_num[ARRAY_SIZE(scan_pins)][ARRAY_SIZE(drive_pins)] = {
    {VK_PAUSE,    VK_POWER,     VK_EURO,      VK_SLEEP,     VK_RCTRL,      VK_WAKEUP,    VK_CTRL,     VK_F5         },
    {VK_Q,        VK_TAB,       VK_A,         VK_ESC,       VK_Z,          VK_NCHG,      VK_TILDE,    VK_1          },
    {VK_W,        VK_CAPITAL,   VK_S,         VK_K45,       VK_X,          VK_CHG,       VK_F1,       VK_2          },
    {VK_E,        VK_F3,        VK_D,         VK_F4,        VK_C,          VK_ROMA,      VK_F2,       VK_3          },
    {VK_R,        VK_T,         VK_F,         VK_G,         VK_V,          VK_B,         VK_5,        VK_4          },
    {VK_U,        VK_Y,         VK_J,         VK_H,         VK_M,          VK_N,         VK_6,        VK_7          },
    {VK_I,        VK_RBRACE,    VK_K,         VK_F6,        VK_COMMA,      VK_K56,       VK_EQUAL,    VK_8          },
    {VK_O,        VK_F7,        VK_L,         VK_RMB,       VK_PERIOD,     VK_APP,       VK_F8,       VK_9          },
    {VK_P,        VK_LBRACE,    VK_SEMICOLON, VK_QUOTE,     VK_BACKSLASH,  VK_SLASH,     VK_MINUS,    VK_0          },
    {VK_SCR_LOCK, VK_C9R1,      VK_FN,        VK_ALT,       VK_MMODE,      VK_RALT,      VK_C9R6,     VK_PRINTSCREEN},
    {VK_K14,      VK_BACKSPACE, VK_BACKSLASH, VK_F11,       VK_ENTER,      VK_F12,       VK_F9,       VK_F10        },
    {VKPAD_7,     VKPAD_4,      VKPAD_1,      VK_SPACE,     VK_NUM_LOCK,   VK_DOWN,      VK_DELETE,   VK_POWER      },
    {VKPAD_8,     VKPAD_5,      VKPAD_2,      VKPAD_0,      VKPAD_SLASH,   VK_RIGHT,     VK_INSERT,   VK_SLEEP      },
    {VKPAD_9,     VKPAD_6,      VKPAD_3,      VKPAD_PERIOD, VKPAD_ASTERIX, VKPAD_MINUS,  VK_PAGE_UP,  VK_PAGE_DOWN  },
    {VKPAD_PLUS,  VK_K107,      VKPAD_ENTER,  VK_UP,        VK_PLAY_PAUSE, VK_LEFT,      VK_HOME,     VK_END        },
    {VK_WAKEUP,   VK_SHIFT,     VK_RSHIFT,    VK_VOL_DN,    VK_VOL_UP,     VK_NEXT_TRK,  VK_PREV_TRK, VK_MEDIA      },
    {VK_MAIL,     VK_WIN,       VK_W_FORWARD, VK_W_STOP,    VK_W_BACK,     VK_W_REFRESH, VK_W_MUTE,   VK_W_SRCH     },
    {VK_KCL,      VK_W_FAV,     VK_RWIN,      VK_MY_COMP,   VK_STOP,       VK_CAL,       VK_WEB,      VK_KCR        },
};
        #else
static const unsigned char kb_map_num[ARRAY_SIZE(scan_pins)][ARRAY_SIZE(drive_pins)] = KB_MAP_NUM;
        #endif

        #ifndef KB_MAP_FN
static const unsigned char kb_map_fn[ARRAY_SIZE(scan_pins)][ARRAY_SIZE(drive_pins)] = {
    {VK_PAUSE,    VK_POWER,     VK_EURO,      VK_SLEEP,     VK_RCTRL,      VK_WAKEUP,    VK_CTRL,     VK_F5         },
    {VK_Q,        VK_TAB,       VK_A,         VK_ESC,       VK_Z,          VK_NCHG,      VK_TILDE,    VK_1          },
    {VK_W,        VK_CAPITAL,   VK_S,         VK_K45,       VK_X,          VK_CHG,       VK_F1,       VK_2          },
    {VK_E,        VK_F3,        VK_D,         VK_F4,        VK_C,          VK_ROMA,      VK_F2,       VK_3          },
    {VK_R,        VK_T,         VK_F,         VK_G,         VK_V,          VK_B,         VK_5,        VK_4          },
    {VK_U,        VK_Y,         VK_J,         VK_H,         VK_M,          VK_N,         VK_6,        VK_7          },
    {VK_I,        VK_RBRACE,    VK_K,         VK_F6,        VK_COMMA,      VK_K56,       VK_EQUAL,    VK_8          },
    {VK_O,        VK_F7,        VK_L,         VK_RMB,       VK_PERIOD,     VK_APP,       VK_F8,       VK_9          },
    {VK_P,        VK_LBRACE,    VK_SEMICOLON, VK_QUOTE,     VK_BACKSLASH,  VK_SLASH,     VK_MINUS,    VK_0          },
    {VK_SCR_LOCK, VK_C9R1,      VK_FN,        VK_ALT,       VK_MMODE,      VK_RALT,      VK_C9R6,     VK_PRINTSCREEN},
    {VK_K14,      VK_BACKSPACE, VK_BACKSLASH, VK_F11,       VK_ENTER,      VK_F12,       VK_F9,       VK_F10        },
    {VKPAD_7,     VKPAD_4,      VKPAD_1,      VK_SPACE,     VK_NUM_LOCK,   VK_DOWN,      VK_DELETE,   VK_POWER      },
    {VKPAD_8,     VKPAD_5,      VKPAD_2,      VKPAD_0,      VKPAD_SLASH,   VK_RIGHT,     VK_INSERT,   VK_SLEEP      },
    {VKPAD_9,     VKPAD_6,      VKPAD_3,      VKPAD_PERIOD, VKPAD_ASTERIX, VKPAD_MINUS,  VK_PAGE_UP,  VK_PAGE_DOWN  },
    {VKPAD_PLUS,  VK_K107,      VKPAD_ENTER,  VK_UP,        VK_PLAY_PAUSE, VK_LEFT,      VK_HOME,     VK_END        },
    {VK_WAKEUP,   VK_SHIFT,     VK_RSHIFT,    VK_VOL_DN,    VK_VOL_UP,     VK_NEXT_TRK,  VK_PREV_TRK, VK_MEDIA      },
    {VK_MAIL,     VK_WIN,       VK_W_FORWARD, VK_W_STOP,    VK_W_BACK,     VK_W_REFRESH, VK_W_MUTE,   VK_W_SRCH     },
    {VK_KCL,      VK_W_FAV,     VK_RWIN,      VK_MY_COMP,   VK_STOP,       VK_CAL,       VK_WEB,      VK_KCR        },
};
        #else
static const unsigned char kb_map_fn[ARRAY_SIZE(scan_pins)][ARRAY_SIZE(drive_pins)] = KB_MAP_FN;
        #endif

kb_k_mp_t *kb_p_map[4] = {
    kb_map_normal,
    kb_map_num,
    kb_map_fn,
    kb_map_fn,
};
#endif

    ///////////////////////////////////////////////////////////////////////
    //////////// load configuration from flash/OTP ////////////////////////
    ///////////////////////////////////////////////////////////////////////
    #else //line 62

    #endif

_attribute_data_retention_ unsigned int scan_pin_need;

static unsigned char kb_is_fn_pressed = 0;

kb_k_mp_t *kb_k_mp;

void kb_rmv_ghost_key(unsigned int *pressed_matrix)
{
    unsigned int mix_final = 0;
    foreach_arr(i, drive_pins)
    {
        for (unsigned int j = (i + 1); j < ARRAY_SIZE(drive_pins); ++j) {
            unsigned int mix = (pressed_matrix[i] & pressed_matrix[j]);
            //four or three key at "#" is pressed at the same time, should remove ghost key
            if (mix && (!BIT_IS_POW2(mix) || (pressed_matrix[i] ^ pressed_matrix[j]))) {
                // remove ghost keys
                //pressed_matrix[i] &= ~mix;
                //pressed_matrix[j] &= ~mix;
                mix_final |= mix;
            }
        }
        pressed_matrix[i] &= ~mix_final;
    }
}

    #if (LONG_PRESS_KEY_POWER_OPTIMIZE)
int key_matrix_same_as_last_cnt = 0; //record key matrix no change cnt
    #endif

unsigned int key_debounce_filter(unsigned int mtrx_cur[], unsigned int filt_en)
{
    unsigned int kc = 0;
    #if (LONG_PRESS_KEY_POWER_OPTIMIZE)
    unsigned char matrix_differ = 0;
    #endif
    static unsigned int mtrx_pre[ARRAY_SIZE(drive_pins)];
    static unsigned int mtrx_last[ARRAY_SIZE(drive_pins)];
    foreach_arr(i, drive_pins)
    {
        unsigned int mtrx_tmp = mtrx_cur[i];
    #if (STUCK_KEY_PROCESS_ENABLE)
        stuckKeyPress[i] = mtrx_tmp ? 1 : 0;
    #endif
        if (filt_en) {
            //mtrx_cur[i] = (mtrx_last[i] ^ mtrx_tmp) ^ (mtrx_last[i] | mtrx_tmp);  //key_matrix_pressed is valid when current and last value is the same
            mtrx_cur[i] = (~mtrx_last[i] & (mtrx_pre[i] & mtrx_tmp)) | (mtrx_last[i] & (mtrx_pre[i] | mtrx_tmp));
        }
        if (mtrx_cur[i] != mtrx_last[i]) {
            kc = 1;
        }
    #if (LONG_PRESS_KEY_POWER_OPTIMIZE)
        if (mtrx_cur[i] ^ mtrx_pre[i]) { //when same, XOR value is 0
            matrix_differ = 1;
        }
    #endif
        mtrx_pre[i]  = mtrx_tmp;
        mtrx_last[i] = mtrx_cur[i];
    }

    #if (LONG_PRESS_KEY_POWER_OPTIMIZE)
    if (matrix_differ) {
        key_matrix_same_as_last_cnt = 0;
    } else {
        key_matrix_same_as_last_cnt++;
    }
    #endif

    return kc;
}

// input:          pressed_matrix,
// key_code:   output keys array
// key_max:    max keys should be returned
static inline void kb_remap_key_row(int drv_ind, unsigned int m, int key_max, kb_data_t *kb_data)
{
    foreach_arr(i, scan_pins)
    {
        if (m & 0x01) {
            unsigned char kc = kb_k_mp[i][drv_ind];
    #if (KB_HAS_CTRL_KEYS)

            if (kc >= VK_CTRL && kc <= VK_RWIN) {
                kb_data->ctrl_key |= BIT(kc - VK_CTRL);
            }
            //else if(kc == VK_MEDIA_END)
            //lock_button_pressed = 1;
            else if (VK_ZOOM_IN == kc || VK_ZOOM_OUT == kc) {
                kb_data->ctrl_key |= VK_MSK_LCTRL;
                kb_data->keycode[kb_data->cnt++] = (VK_ZOOM_IN == kc) ? VK_EQUAL : VK_MINUS;
            } else if (kc != VK_FN) { //fix fn ghost bug
                kb_data->keycode[kb_data->cnt++] = kc;
            }

    #else
            kb_data->keycode[kb_data->cnt++] = kc;
    #endif
            if (kb_data->cnt >= key_max) {
                break;
            }
        }
        m = m >> 1;
        if (!m) {
            break;
        }
    }
}

static inline void kb_remap_key_code(unsigned int *pressed_matrix, int key_max, kb_data_t *kb_data, int numlock_status)
{
    (void)numlock_status;

    #if (KB_STANDARD_KEYBOARD)
        kb_k_mp = kb_p_map[(numlock_status & 1) | (kb_is_fn_pressed << 1)];
    #else
        kb_k_mp = (kb_k_mp_t *)&kb_map_normal[0];
    #endif
    foreach_arr(i, drive_pins)
    {
        unsigned int m = pressed_matrix[i];
        if (!m) {
            continue;
        }
        kb_remap_key_row(i, m, key_max, kb_data);
        if (kb_data->cnt >= key_max) {
            break;
        }
    }
}

unsigned int kb_scan_row(int drv_ind, unsigned char *gpio)
{
    /*
     * set as gpio mode if using spi flash pin
     * */
    unsigned char sr = irq_disable();
    #if (KB_KEY_FLASH_PIN_MULTI_USE)
    MSPI_AS_GPIO;
    #endif

    #if (!KB_LINE_MODE)
    unsigned int drv_pin = drive_pins[drv_ind];
    if (KB_LINE_HIGH_VALID) {
        gpio_set_high_level(drv_pin);
    } else {
        gpio_set_low_level(drv_pin);
    }
    gpio_output_en(drv_pin);
    #endif

    unsigned int matrix = 0;
    foreach_arr(j, scan_pins)
    {
        if (scan_pin_need & BIT(j)) {
            int key = !gpio_read_cache(scan_pins[j], gpio);
            if (KB_LINE_HIGH_VALID != key) {
                if (KB_HAS_FN_KEY && (kb_k_mp[j][drv_ind] == VK_FN)) {
                    kb_is_fn_pressed = 1;
                }
                matrix |= (1 << j);
            }
        }
    }
    //sleep_us(KB_DRV_DELAY_TIME);
    gpio_read_all(gpio);
    /*
     * set as spi mode  if using spi flash pin
     * */
    #if (KB_KEY_FLASH_PIN_MULTI_USE)
    MSPI_AS_SPI;
    #endif

    #if (!KB_LINE_MODE)
    ////////        float drive pin ////////////////////////////
    //sleep_us(KB_SCAN_DELAY_TIME);
    gpio_set_low_level(drv_pin);
    gpio_output_dis(drv_pin);
    #endif

    irq_restore(sr);
    return matrix;
}

unsigned int matrix_buff[4][ARRAY_SIZE(drive_pins)];
int          matrix_wptr, matrix_rptr;

unsigned int kb_key_pressed(unsigned char *gpio)
{
    foreach_arr(i, drive_pins)
    {
        if (KB_LINE_HIGH_VALID) {
            gpio_set_high_level(drive_pins[i]);
        } else {
            gpio_set_low_level(drive_pins[i]);
        }
        gpio_output_en(drive_pins[i]);
    }
    sleep_us(20);
    gpio_read_all(gpio);

    unsigned int         ret         = 0;
    static unsigned char release_cnt = 0;
    static unsigned int  ret_last    = 0;

    foreach_arr(i, scan_pins)
    {
        if (KB_LINE_HIGH_VALID != !gpio_read_cache(scan_pins[i], gpio)) {
            ret |= (1 << i);
            release_cnt = 6;
            ret_last    = ret;
        }
    }
    if (release_cnt) {
        ret = ret_last;
        release_cnt--;
    }
    foreach_arr(i, drive_pins)
    {
        gpio_set_low_level(drive_pins[i]);
        gpio_output_dis(drive_pins[i]);
    }
    return ret;
}

unsigned int kb_scan_key_value(int numlock_status, int read_key, unsigned char *gpio)
{
    kb_event.cnt      = 0;
    kb_event.ctrl_key = 0;
    kb_is_fn_pressed  = 0;

    unsigned int pressed_matrix[ARRAY_SIZE(drive_pins)] = {0};
    #if (KB_STANDARD_KEYBOARD)
        kb_k_mp = kb_p_map[0];
    #else
        kb_k_mp = (kb_k_mp_t *)&kb_map_normal[0];
    #endif

    kb_scan_row(0, gpio);
    for (unsigned int i = 0; i <= ARRAY_SIZE(drive_pins); i++) {
        unsigned int r = kb_scan_row(i < ARRAY_SIZE(drive_pins) ? i : 0, gpio);
        if (i) {
            pressed_matrix[i - 1] = r;
        }
    }

    #if (KB_RM_GHOST_KEY_EN)
    kb_rmv_ghost_key(&pressed_matrix[0]);
    #endif

    unsigned int key_changed = key_debounce_filter(pressed_matrix,
                                                   (numlock_status & KB_NUMLOCK_STATUS_POWERON) ? 0 : 1);

    #if (KB_REPEAT_KEY_ENABLE)
    if (key_changed) {
        repeat_key.key_change_flg  = KEY_CHANGE;
        repeat_key.key_change_tick = stimer_get_tick();
    } else {
        if (repeat_key.key_change_flg == KEY_CHANGE) {
            repeat_key.key_change_flg = KEY_SAME;
        }

        if (repeat_key.key_change_flg == KEY_SAME && repeat_key.key_repeat_flg &&
            clock_time_exceed(repeat_key.key_change_tick, (KB_REPEAT_KEY_INTERVAL_MS - 5) * 1000)) {
            repeat_key.key_change_tick = stimer_get_tick();
            key_changed                = 1;
        }
    }
    #endif

    ///////////////////////////////////////////////////////////////////
    //  insert buffer here
    //       key mapping requires NUMLOCK status
    ///////////////////////////////////////////////////////////////////
    unsigned int *pd;
    if (key_changed) {
        /////////// push to matrix buffer /////////////////////////
        pd = matrix_buff[matrix_wptr & 3];
        for (unsigned int k = 0; k < ARRAY_SIZE(drive_pins); k++) {
            *pd++ = pressed_matrix[k];
        }
        matrix_wptr = (matrix_wptr + 1) & 7;
        if (((matrix_wptr - matrix_rptr) & 7) > 4) { //overwrite older data
            matrix_rptr = (matrix_wptr - 4) & 7;
        }
    }

    if (numlock_status & KB_NUMLOCK_STATUS_INVALID) {
        return 1; //return empty key
    }

    ////////// read out //////////
    if (matrix_wptr == matrix_rptr || !read_key) {
        return 0; //buffer empty, no data
    }
    pd          = matrix_buff[matrix_rptr & 3];
    matrix_rptr = (matrix_rptr + 1) & 7;

    ///////////////////////////////////////////////////////////////////
    kb_remap_key_code(pd, KB_RETURN_KEY_MAX, &kb_event, numlock_status);

    #if (KB_REPEAT_KEY_ENABLE)
    if (repeat_key.key_change_flg == KEY_CHANGE) {
        repeat_key.key_repeat_flg = 0;

        if (kb_event.cnt == 1) { //handle one key repeat only
            for (int i = 0; i < KB_REPEAT_KEY_NUM; i++) {
                if (kb_event.keycode[0] == kb_map_repeat[i]) {
                    repeat_key.key_repeat_flg = 1;
                    break;
                }
            }
        }
    }
    #endif

    return 1;
}


#endif


///////////////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////////////
